package server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server implements Runnable{
	final int NUM_ENTRIES = 10;

	boolean isReading;
	static ScoreEntry[] entries;

	public Server(boolean isReading){
		this.isReading = isReading;


		// reading thread will create the static entry table
		/* 
		 * PROTIP: the big assumption here is that scores.dat
		 * both already exists in data/server/ AND contains 
		 * ten entries that are already sorted
		 * */
		if(isReading){

			// create entry objects
			entries = new ScoreEntry[NUM_ENTRIES];
			for(int i=0; i<NUM_ENTRIES; i++){
				entries[i] = new ScoreEntry();
			}

			// process ze input file
			try {
				System.out.println("Reader: Reading scores.dat");
				FileInputStream fstream = new FileInputStream("data/server/scores.dat");
				DataInputStream in = new DataInputStream(fstream);
				BufferedReader br = new BufferedReader(new InputStreamReader(in));
				String line;
				int i = 0;
				while ((line = br.readLine()) != null){
					String[] lineData = line.split("\\s");
					entries[i].setVals(lineData[0], Integer.parseInt(lineData[1]));
					i++;
				}
				if(i < NUM_ENTRIES-1){
					System.out.println("Reader: warning: not enough entries in file");	
				}
				in.close();
				br.close();

			} catch (Exception e){
				System.out.println("Reader: Error reading HS table");
			}
		}
	}

	public void run() {
		while (true){
			if (isReading){
				// READING THREAD -- Returns a list of high scores from server to client
				ServerSocket ss;

				try {
					ss = new ServerSocket(25402);

					while (true){
						System.out.println("Reader: Waiting for connection...");
						Socket channel = ss.accept();
						PrintWriter toClient = new PrintWriter(channel.getOutputStream(), true);
						for(int i=0; i<entries.length;i++){
							if(entries[i] != null){
								toClient.println(entries[i].name + " " + entries[i].score);
							} else {
								System.out.println("null entry: " + i);
							}
						}
						toClient.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}


			} else {
				// WRITING THREAD -- Writes all the high scores from client to server
				ServerSocket ss;
				try {

					// create a server listening for requests
					ss = new ServerSocket(25401);

					while(true){
						System.out.println("Writer: Waiting for connection...");
						Socket channel = ss.accept();

						// get input/output streams from channel socket
						OutputStream out = channel.getOutputStream();
						PrintStream pout = new PrintStream(out);
						InputStream in = channel.getInputStream();
						BufferedReader din = new BufferedReader(new InputStreamReader(in));

						//read from input stream to get client potential score
						String name = din.readLine();
						String score = din.readLine();
						ScoreEntry potential = new ScoreEntry();
						potential.setVals(name, Integer.parseInt(score));

						System.out.println("Writer: got scores, checking if it will go on the table");
						boolean rewrite = false;
						for(int i=0; i<NUM_ENTRIES; i++){
							if(potential.score > entries[i].score){
								rewrite = true;
								for(int j=NUM_ENTRIES-1; j>i; j--){
									entries[j] = entries[j-1];
								}
								entries[i] = potential;
								System.out.println("Writer: This entry is position " + (i+1));
								break;
							}
						}

						// write the new high score file to disk?
						if(rewrite){
							
							System.out.println("Writer: creating new scores.dat file");
							try{
								FileWriter fstream = new FileWriter("data/server/scores.dat");
								BufferedWriter outpt = new BufferedWriter(fstream);
								for(int i=0; i<NUM_ENTRIES; i++){
									if(entries[i] != null){
										outpt.write(entries[i].name + " " + entries[i].score + System.getProperty("line.separator"));
									} else {
										System.out.println("Writer: warning, entry " + i + " is null");
									}
								}
								outpt.close();
								
							} catch (Exception e){
								System.out.println("Writer: cannot create new file");
							}
							
						}

						// close everything
						din.close();
						pout.close();
						channel.close();
					}

				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void main(String[] args) {
		Server reader = new Server(true);
		Server writer = new Server(false);
		Thread readThread = new Thread(reader);
		Thread writeThread = new Thread(writer);
		readThread.start();
		writeThread.start();

	}
}
